{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "06a3bbec",
   "metadata": {},
   "source": [
    "下面用代码实现循环神经网络。首先读取数据，使用《小王子》这本书作为训练语料。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "58df11c1",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "115\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import os\n",
    "import sys\n",
    "\n",
    "# 导入前面实现的小王子数据集\n",
    "sys.path.append('./code')\n",
    "from my_utils import TheLittlePrinceDataset\n",
    "\n",
    "dataset = TheLittlePrinceDataset()\n",
    "\n",
    "# 统计每句话的长度\n",
    "sent_lens = []\n",
    "max_len = -1\n",
    "for sentence in dataset.tokens:\n",
    "    sent_len = len(sentence)\n",
    "    sent_lens.append(sent_len)\n",
    "    if sent_len > max_len:\n",
    "        max_len = sent_len\n",
    "        longest = sentence\n",
    "print(max_len)\n",
    "\n",
    "# 简单看一下语料中序列长度的分布\n",
    "import matplotlib.pyplot as plt\n",
    "plt.hist(sent_lens, bins=20)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf1e69d9",
   "metadata": {},
   "source": [
    "接下来建立词表，截断过长的序列，将序列填充（padding）到相同长度。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "f25456ee",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1089 115\n",
      "(1088, 40)\n",
      "[  4  16  19 733 734 735 733 734 735   2  63  20   9   1   1   2   1  10\n",
      " 736 737   4  16  19  21   1   2  30 371 209  33 294   3   0   0   0   0\n",
      "   0   0   0   0]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "dataset.build_vocab()\n",
    "sent_tokens = dataset.convert_tokens_to_ids()\n",
    "# 截断和填充\n",
    "max_len=40\n",
    "for i, tokens in enumerate(sent_tokens):\n",
    "    tokens = tokens[:max_len]\n",
    "    tokens += [dataset.token2id['<pad>']] * (max_len - len(tokens))\n",
    "    sent_tokens[i] = tokens\n",
    "sent_tokens = np.array(sent_tokens)\n",
    "\n",
    "print(len(dataset.tokens), max([len(x) for x in dataset.tokens]))\n",
    "print(sent_tokens.shape)\n",
    "print(sent_tokens[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "06e6fb52",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "import torch\n",
    "from torch import nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "# 定义一个正态分布的函数用于初始化参数\n",
    "def normal(shape):\n",
    "    return torch.randn(size=shape) * 0.01\n",
    "\n",
    "class RNN(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size):\n",
    "        super(RNN, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        # 将输入与隐状态分别经过线性变化后相加\n",
    "        self.W_xh = nn.Parameter(normal((input_size, hidden_size)))\n",
    "        self.W_hh = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_h = nn.Parameter(torch.zeros(hidden_size))\n",
    "    \n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((batch_size, hidden_size), dtype=torch.float),)\n",
    "    \n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        hidden_state, = states\n",
    "        hiddens = []\n",
    "        for step in range(seq_len):\n",
    "            # 输入hidden_state与inputs经过线性变换后相加，\n",
    "            # 输出的hidden_state也是下一时刻输入的hidden_state\n",
    "            xh = torch.mm(inputs[step], self.W_xh)\n",
    "            hh = torch.mm(hidden_state, self.W_hh)\n",
    "            hidden_state = xh + hh + self.b_h\n",
    "            hidden_state = torch.tanh(hidden_state)\n",
    "            hiddens.append(hidden_state)\n",
    "        # 返回所有时刻的hidden_state: seq_len * batch_size * hidden_size\n",
    "        # 以及最后时刻的hidden_state（可能用于后续输入）: \n",
    "        # batch_size * hidden_size\n",
    "        return torch.stack(hiddens, dim=0), (hidden_state,)\n",
    "\n",
    "# 在循环神经网络的基础上添加语言模型的输入输出、损失计算等\n",
    "class RNNLM(nn.Module):\n",
    "    def __init__(self, model, vocab_size, hidden_size):\n",
    "        super(RNNLM, self).__init__()\n",
    "        self.vocab_size = vocab_size\n",
    "        self.hidden_size = hidden_size\n",
    "        self.embedding = nn.Embedding(vocab_size, hidden_size)\n",
    "        self.model = model\n",
    "        self.W_hq = nn.Parameter(normal((hidden_size, vocab_size)))\n",
    "        self.b_q = nn.Parameter(torch.zeros(vocab_size))\n",
    "        \n",
    "    def forward(self, input_ids):\n",
    "        batch_size, seq_len = input_ids.shape\n",
    "        # input_ids形状为batch_size * seq_len，翻转为seq_len * batch_size，\n",
    "        # 将seq_len放在第一维方便计算\n",
    "        input_ids = torch.permute(input_ids, (1, 0))\n",
    "        # seq_len * batch_size * embed_size\n",
    "        embed = self.embedding(input_ids)\n",
    "        # batch_size * hidden_size\n",
    "        states = self.model.init_rnn_state(batch_size, self.hidden_size)\n",
    "        hiddens, _ = self.model(embed, states)\n",
    "    \n",
    "        hiddens = torch.flatten(hiddens[:-1], start_dim=0, end_dim=1)\n",
    "        output_states = torch.mm(hiddens, self.W_hq) + self.b_q\n",
    "        labels = torch.flatten(input_ids[1:], start_dim=0, end_dim=1)\n",
    "        loss_fct = nn.CrossEntropyLoss(ignore_index=0)\n",
    "        loss = loss_fct(output_states, labels)\n",
    "        return loss"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "45a010aa",
   "metadata": {},
   "source": [
    "下面展示使用梯度裁剪的循环神经网络语言模型的训练代码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "760da2e1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1088, 40)\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=0.4447: 100%|█| 200/200 [03:07<00:00,  1.07i\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 梯度裁剪\n",
    "def grad_clipping(model, theta=1):\n",
    "    params = [p for p in model.parameters() if p.requires_grad]\n",
    "    norm = torch.sqrt(sum(torch.sum((p.grad ** 2)) for p in params))\n",
    "    if norm > theta:\n",
    "        for param in params:\n",
    "            param.grad[:] *= theta / norm\n",
    "    \n",
    "\n",
    "# 训练\n",
    "from torch.utils.data import DataLoader\n",
    "from torch.optim import SGD, Adam\n",
    "import numpy as np\n",
    "from tqdm import tqdm, trange\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "def train_rnn_lm(data_loader, rnn, vocab_size, hidden_size=128, \n",
    "                 epochs=200, learning_rate=1e-3):\n",
    "    # 准备模型、优化器等\n",
    "    rnn_lm = RNNLM(rnn, vocab_size, hidden_size)\n",
    "    optimizer = Adam(rnn_lm.parameters(), lr=learning_rate)\n",
    "    rnn_lm.zero_grad()\n",
    "    rnn_lm.train()\n",
    "\n",
    "    epoch_loss = []\n",
    "    with trange(epochs, desc='epoch', ncols=60) as pbar:\n",
    "        for epoch in pbar:\n",
    "            for step, batch in enumerate(data_loader):\n",
    "                loss = rnn_lm(batch)\n",
    "                pbar.set_description(f'epoch-{epoch}, ' + \\\n",
    "                    f'loss={loss.item():.4f}')\n",
    "                loss.backward()\n",
    "                grad_clipping(rnn_lm)\n",
    "                optimizer.step()\n",
    "                rnn_lm.zero_grad()\n",
    "            epoch_loss.append(loss.item())\n",
    "\n",
    "    epoch_loss = np.array(epoch_loss)\n",
    "    # 打印损失曲线\n",
    "    plt.plot(range(len(epoch_loss)), epoch_loss)\n",
    "    plt.xlabel('training epoch')\n",
    "    plt.ylabel('loss')\n",
    "    plt.show()\n",
    "\n",
    "sent_tokens = np.array(sent_tokens)\n",
    "print(sent_tokens.shape)\n",
    "vocab_size = len(dataset.token2id)\n",
    "\n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, dtype=torch.long),\\\n",
    "    batch_size=16, shuffle=True)\n",
    "rnn = RNN(128, 128)\n",
    "train_rnn_lm(data_loader, rnn, vocab_size, hidden_size=128,\\\n",
    "    epochs=200, learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ad30e705",
   "metadata": {},
   "source": [
    "接下来仿照循环神经网络实现长短期记忆，同样的接口使得我们可以重用之前的训练代码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1995d027",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=0.2949: 100%|█| 200/200 [12:22<00:00,  3.71s\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 长短期记忆\n",
    "def gate_params(input_size, hidden_size):\n",
    "    return (nn.Parameter(normal((input_size, hidden_size))),\n",
    "           nn.Parameter(normal((hidden_size, hidden_size))),\n",
    "           nn.Parameter(torch.zeros(hidden_size)))\n",
    "\n",
    "class LSTM(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size):\n",
    "        super(LSTM, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        # 输入门参数\n",
    "        self.W_xi, self.W_hi, self.b_i = gate_params(input_size, hidden_size)\n",
    "        # 遗忘门参数\n",
    "        self.W_xf, self.W_hf, self.b_f = gate_params(input_size, hidden_size)\n",
    "        # 输出门参数\n",
    "        self.W_xo, self.W_ho, self.b_o = gate_params(input_size, hidden_size)\n",
    "        # 候选记忆单元参数\n",
    "        self.W_xc, self.W_hc, self.b_c = gate_params(input_size, hidden_size)\n",
    "        \n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((batch_size, hidden_size), dtype=torch.float),\n",
    "               torch.zeros((batch_size, hidden_size), dtype=torch.float))\n",
    "    \n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        hidden_state, cell_state = states\n",
    "        hiddens = []\n",
    "        for step in range(seq_len):\n",
    "            I = torch.sigmoid(torch.mm(inputs[step], self.W_xi) \\\n",
    "                + torch.mm(hidden_state, self.W_hi) + self.b_i)\n",
    "            F = torch.sigmoid(torch.mm(inputs[step], self.W_xf) \\\n",
    "                + torch.mm(hidden_state, self.W_hf) + self.b_f)\n",
    "            O = torch.sigmoid(torch.mm(inputs[step], self.W_xo) \\\n",
    "                + torch.mm(hidden_state, self.W_ho) + self.b_o)\n",
    "            C_tilda = torch.tanh(torch.mm(inputs[step], self.W_xc) \\\n",
    "                + torch.mm(hidden_state, self.W_hc) + self.b_c)\n",
    "            cell_state = F * cell_state + I * C_tilda\n",
    "            hidden_state = O * torch.tanh(cell_state)\n",
    "            hiddens.append(hidden_state)\n",
    "        return torch.stack(hiddens, dim=0), (hidden_state, cell_state)\n",
    "    \n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, dtype=torch.long), \n",
    "    batch_size=16, shuffle=True)\n",
    "\n",
    "lstm = LSTM(128, 128)\n",
    "train_rnn_lm(data_loader, lstm, vocab_size, hidden_size=128, epochs=200, \n",
    "    learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e6dafe1d",
   "metadata": {},
   "source": [
    "下面仿照长短期记忆实现门控循环单元。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7c4f3992",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=0.2947: 100%|█| 200/200 [11:40<00:00,  3.50s\n"
     ]
    },
    {
     "data": {
      "image/png": "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Tz75hJ07d3LhhRcece5NN93kcl9ffvnlzmh+qxzrHsKxfy676j0EXK4rNzeXN954A4vFwqWXXupyniffw9Z8RnjE76IhLk455RTjlltucTk2ePBg43e/+52bWtRxCgoKDMBYsmSJeez66683Zs2a5b5GHaeHH37YGDVqVLPP2Ww2IyEhwXj88cfNYzU1NUZ4eLjxr3/9q5Na2PHuuusuo1+/fobNZjMMo+vfQ8D49NNPzcetuW8lJSWGr6+v8f7775vnHDhwwPDy8jK++eabTmt7axx+fc1ZtWqVARj79+83j02ZMsW46667TmzjOkhz13isn8vudg9nzZplnHnmmS7HutI9NIwjPyM85XdRPSpN1NXVsXbtWqZPn+5yfPr06fz4449ualXHKS0tBSAqKsrl+OLFi4mLi2PgwIHcdNNNFBQUuKN57bZr1y6SkpLo06cPV155JXv37gUgIyODvLw8l/vp7+/PlClTuuz9rKur49133+XGG2902Yizq9/Dplpz39auXUt9fb3LOUlJSQwfPrxL3tvS0lIsFgsREREux//zn/8QExPDsGHDuO+++7pUTyAc/eeyO93D/Px85s2bxy9/+csjnutK9/DwzwhP+V10+xL6nqSwsBCr1Up8fLzL8fj4ePLy8tzUqo5hGAb33HMPkyZNYvjw4ebxGTNm8LOf/Yy0tDQyMjJ46KGHOPPMM1m7dm2XWGVx/PjxvPPOOwwcOJD8/Hz+8pe/MHHiRLZs2WLes+bu5/79+93R3OM2d+5cSkpKuOGGG8xjXf0eHq419y0vLw8/Pz8iIyOPOKer/a7W1NTwu9/9jquvvtpls7drrrmGPn36kJCQwObNm5k9ezYbNmwwh/483bF+LrvTPXz77bcJDQ3lkksucTnele5hc58RnvK7qKDSjKb/UwX7DTz8WFdz++23s3HjRpYvX+5y/IorrjC/Hz58OOPGjSMtLY158+Yd8UvniWbMmGF+P2LECCZMmEC/fv14++23zcK97nQ/X3/9dWbMmOGyNXpXv4ctac9962r3tr6+niuvvBKbzcaLL77o8txNN91kfj98+HAGDBjAuHHjWLduHWPGjOnsprZZe38uu9o9BHjjjTe45pprCAgIcDnele5hS58R4P7fRQ39NBETE4O3t/cRKbCgoOCIRNmV3HHHHXz++ecsWrSI5OTko56bmJhIWloau3bt6qTWdazg4GBGjBjBrl27zNk/3eV+7t+/n4ULF/KrX/3qqOd19XvYmvuWkJBAXV0dxcXFLZ7j6err67n88svJyMhgwYIFLr0pzRkzZgy+vr5d9r4e/nPZHe4hwLJly9ixY8cxfy/Bc+9hS58RnvK7qKDShJ+fH2PHjj2iW27BggVMnDjRTa1qP8MwuP322/nkk0/4/vvv6dOnzzFfU1RURFZWFomJiZ3Qwo5XW1vLtm3bSExMNLtcm97Puro6lixZ0iXv55tvvklcXBznn3/+Uc/r6vewNfdt7Nix+Pr6upyTm5vL5s2bu8S9dYaUXbt2sXDhQqKjo4/5mi1btlBfX99l7+vhP5dd/R46vf7664wdO5ZRo0Yd81xPu4fH+ozwmN/FDinJ7Ubef/99w9fX13j99deNrVu3GnfffbcRHBxs7Nu3z91Na7Pf/OY3Rnh4uLF48WIjNzfX/KqqqjIMwzDKy8uNe++91/jxxx+NjIwMY9GiRcaECROMXr16GWVlZW5ufevce++9xuLFi429e/caK1asMGbOnGmEhoaa9+vxxx83wsPDjU8++cTYtGmTcdVVVxmJiYld5vqcrFarkZqaajz44IMux7vqPSwvLzfS09ON9PR0AzCeeuopIz093Zz10pr7dssttxjJycnGwoULjXXr1hlnnnmmMWrUKKOhocFdl2U62vXV19cbF154oZGcnGysX7/e5XeztrbWMAzD2L17t/HnP//ZWL16tZGRkWHMmzfPGDx4sDF69GiPuD7DOPo1tvbnsqveQ6fS0lIjKCjIeOmll454fVe4h8f6jDAMz/hdVFBpxgsvvGCkpaUZfn5+xpgxY1ym83YlQLNfb775pmEYhlFVVWVMnz7diI2NNXx9fY3U1FTj+uuvNzIzM93b8Da44oorjMTERMPX19dISkoyLrnkEmPLli3m8zabzXj44YeNhIQEw9/f35g8ebKxadMmN7a4fb799lsDMHbs2OFyvKvew0WLFjX7s3n99dcbhtG6+1ZdXW3cfvvtRlRUlBEYGGjMnDnTY677aNeXkZHR4u/mokWLDMMwjMzMTGPy5MlGVFSU4efnZ/Tr18+48847jaKiIvdeWBNHu8bW/lx21Xvo9PLLLxuBgYFGSUnJEa/vCvfwWJ8RhuEZv4sWR2NFREREPI5qVERERMRjKaiIiIiIx1JQEREREY+loCIiIiIeS0FFREREPJaCioiIiHgsBRURERHxWAoqIiIi4rEUVESkVXr37s3TTz/d6vMXL16MxWKhpKTkhLXJk7T170dEWsfH3Q0QkRNj6tSpnHTSSR324bl69WqCg4Nbff7EiRPJzc0lPDy8Q/58EemZFFREejDDMLBarfj4HPufgtjY2Da9t5+fn7lNvIhIe2noR6QbuuGGG1iyZAnPPPMMFosFi8XCvn37zOGYb7/9lnHjxuHv78+yZcvYs2cPs2bNIj4+npCQEE4++WQWLlzo8p6HD21YLBZee+01Lr74YoKCghgwYACff/65+fzhQz9vvfUWERERfPvttwwZMoSQkBDOPfdccnNzzdc0NDRw5513EhERQXR0NA8++CDXX389F1100VGv98cff2Ty5MkEBgaSkpLCnXfeSWVlpUvbH330Ua6++mpCQkJISkriueeec3mPzMxMZs2aRUhICGFhYVx++eXk5+e7nPP5558zbtw4AgICiImJ4ZJLLnF5vqqqihtvvJHQ0FBSU1N55ZVXjtpuETk2BRWRbuiZZ55hwoQJ3HTTTeTm5pKbm0tKSor5/AMPPMCcOXPYtm0bI0eOpKKigvPOO4+FCxeSnp7OOeecwwUXXEBmZuZR/5w///nPXH755WzcuJHzzjuPa665hkOHDrV4flVVFX//+9/597//zdKlS8nMzOS+++4zn//b3/7Gf/7zH958801++OEHysrKmDt37lHbsGnTJs455xwuueQSNm7cyAcffMDy5cu5/fbbXc578sknGTlyJOvWrWP27Nn89re/ZcGCBYC9Z+miiy7i0KFDLFmyhAULFrBnzx6uuOIK8/Xz5s3jkksu4fzzzyc9PZ3vvvuOcePGufwZ//jHPxg3bhzp6enceuut/OY3v2H79u1Hbb+IHEOH7cMsIh5lypQpxl133eVyzLl1/dy5c4/5+qFDhxrPPfec+TgtLc345z//aT4GjD/+8Y/m44qKCsNisRhff/21y59VXFxsGIZhvPnmmwZg7N6923zNCy+8YMTHx5uP4+PjjSeffNJ83NDQYKSmphqzZs1qsZ3XXnutcfPNN7scW7ZsmeHl5WVUV1ebbT/33HNdzrniiiuMGTNmGIZhGPPnzze8vb1dtqbfsmWLARirVq0yDMMwJkyYYFxzzTUttiMtLc34+c9/bj622WxGXFyc8dJLL7X4GhE5NvWoiPRAh/cEVFZW8sADDzB06FAiIiIICQlh+/btx+xRGTlypPl9cHAwoaGhFBQUtHh+UFAQ/fr1Mx8nJiaa55eWlpKfn88pp5xiPu/t7c3YsWOP2oa1a9fy1ltvERISYn6dc8452Gw2MjIyzPMmTJjg8roJEyawbds2ALZt20ZKSopLr5Pz78J5zvr16znrrLOO2pamfx8Wi4WEhISj/n2IyLGpmFakBzp89s7999/Pt99+y9///nf69+9PYGAgl112GXV1dUd9H19fX5fHFosFm83WpvMNwzjiWFOHP384m83Gr3/9a+68884jnktNTT3qa51/lmEYR/y5hx8PDAw86ntB2/8+ROTY1KMi0k35+flhtVpbde6yZcu44YYbuPjiixkxYgQJCQns27fvxDbwMOHh4cTHx7Nq1SrzmNVqJT09/aivGzNmDFu2bKF///5HfPn5+ZnnrVixwuV1K1asYPDgwYC99yQzM5OsrCzz+a1bt1JaWsqQIUMAe2/Jd999d9zXKSJtox4VkW6qd+/erFy5kn379hESEkJUVFSL5/bv359PPvmECy64AIvFwkMPPeSWnoA77riDOXPm0L9/fwYPHsxzzz1HcXFxs70dTg8++CCnnnoqt912GzfddBPBwcFs27aNBQsWuMzs+eGHH3jiiSe46KKLWLBgAR999BHz5s0DYNq0aYwcOZJrrrmGp59+moaGBm699VamTJliDpM9/PDDnHXWWfTr148rr7yShoYGvv76ax544IET+5ci0sOpR0Wkm7rvvvvw9vZm6NChxMbGHrXe5J///CeRkZFMnDiRCy64gHPOOYcxY8Z0YmvtHnzwQa666iquu+46JkyYYNabBAQEtPiakSNHsmTJEnbt2sXpp5/O6NGjeeihh0hMTHQ5795772Xt2rWMHj2aRx99lH/84x+cc845gH2IZu7cuURGRjJ58mSmTZtG3759+eCDD8zXT506lY8++ojPP/+ck046iTPPPJOVK1eemL8IETFZjGMNAIuIuInNZmPIkCFcfvnlPProo+1+n969e3P33Xdz9913d1zjRKRTaOhHRDzG/v37mT9/PlOmTKG2tpbnn3+ejIwMrr76anc3TUTcREM/IuIxvLy8eOuttzj55JM57bTT2LRpEwsXLjQLWkWk59HQj4iIiHgs9aiIiIiIx1JQEREREY+loCIiIiIeS0FFREREPJaCioiIiHgsBRURERHxWAoqIiIi4rEUVERERMRj/T8k6r65qcyN9AAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 门控循环单元\n",
    "class GRU(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size):\n",
    "        super(GRU, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        # 更新门参数\n",
    "        self.W_xu, self.W_hu, self.b_u = gate_params(input_size, hidden_size)\n",
    "        # 重置门参数\n",
    "        self.W_xr, self.W_hr, self.b_r = gate_params(input_size, hidden_size)\n",
    "        # 候选隐状态参数\n",
    "        self.W_xh, self.W_hh, self.b_h = gate_params(input_size, hidden_size)\n",
    "        \n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((batch_size, hidden_size), dtype=torch.float),)\n",
    "    \n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        hidden_state, = states\n",
    "        hiddens = []\n",
    "        for step in range(seq_len):\n",
    "            U = torch.sigmoid(torch.mm(inputs[step], self.W_xu)\\\n",
    "                + torch.mm(hidden_state, self.W_hu) + self.b_u)\n",
    "            R = torch.sigmoid(torch.mm(inputs[step], self.W_xr)\\\n",
    "                + torch.mm(hidden_state, self.W_hr) + self.b_r)\n",
    "            H_tilda = torch.tanh(torch.mm(inputs[step], self.W_xh)\\\n",
    "                + torch.mm(R * hidden_state, self.W_hh) + self.b_h)\n",
    "            hidden_state = (1 - U) * hidden_state + U * H_tilda\n",
    "            hiddens.append(hidden_state)\n",
    "        return torch.stack(hiddens, dim=0), (hidden_state,)\n",
    "    \n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, dtype=torch.long), \n",
    "    batch_size=16, shuffle=True)\n",
    "\n",
    "gru = GRU(128, 128)\n",
    "train_rnn_lm(data_loader, gru, vocab_size, hidden_size=128, epochs=200, \n",
    "    learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69537480",
   "metadata": {},
   "source": [
    "下面在循环神经网络的基础上实现多层循环神经网络。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6eb2e0ed",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=0.4688: 100%|█| 200/200 [07:18<00:00,  2.19s\n"
     ]
    },
    {
     "data": {
      "image/png": "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S8lyAuEB3vx2an8e+mQTPp4Wbhrf65hzmltUKusaKa9tJMTPq5OrFBGR7qhNQeXll1/m97//PTk5OXzyySdEREQAsG7dOq699tozKsg0Terq6s7oPeT0XTkinpoGK4nh/kQGHhsG/bw9CA/w5lBVPftLahRURESkU7QpqISGhvLSSy8dc/x0x4/89re/ZerUqSQkJFBRUcEHH3zAkiVL+Prrr9tSlpwBi8Vg1rheJzwnLtSXQ1X1HCitYUBccOcUJiIi3Vqbxqh8/fXXLF++3PH45Zdf5qyzzuK6666jpKTklN+noKCAG264gb59+3LBBRewatUqvv76ay666KK2lCUdrGcruy2vzjrEla+sYPP+MmeVJSIiXVibgspvfvMbx9TgjIwMHnjgAS655BIyMzO5//77T/l9Xn/9dfbu3UtdXR2FhYUsWrRIIcWFxbWylsrHa3NYu6+EeRsPHO9lIiIibdamrp+srCzHFOJPPvmEadOm8dRTT7F+/XouueSSdi1QXEdrLSrNnxdVaFyRiIi0vza1qHh7e1NdXQ3AokWLmDx5MgDh4eFahK0LO1FQOVipoCIiIu2vTS0q55xzDvfffz/jx49n9erVfPjhhwDs3LmT+Pj4di1QXMfRXT82m0le0wJwRZX1TqtLRES6rja1qLz00kt4enryv//9j1deeYWePXsC8NVXXzFlypR2LVBcR3yYPagUlNdR22ClqLKOeqsNgCK1qIiISAdoU4tKYmIiX3zxxTHH//rXv55xQeK6wgO8CfHzoqymgayiKmoarI7nDlXVY7OZWCyGEysUEZGupk1BBeybCM6dO5dt27ZhGAb9+/dnxowZeHh4tGd94kIMwyAlKoD07FL2HKxs8ZzVZlJSXU9EK4vFiYiItFWbgsru3bu55JJL2L9/P3379sU0TXbu3ElCQgLz588nNTW1vesUF5ESGUh6dimZB6vw8WzZc1hUqaAiIiLtq01jVO655x5SU1PJyclh/fr1pKenk52dTXJyMvfcc0971yguJCUqAIDMg5UtZv+AxqmIiEj7a1OLytKlS1m5ciXh4eGOYxERETz99NOMHz++3YoT15PaHFSKqogOatl6oqAiIiLtrU1BxcfHh4qKimOOV1ZW4u3tfcZFietKiQoEIPNgFfWN9hk/wb6elNc2clCLvomISDtrU9fPtGnTuPXWW1m1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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 多层循环神经网络\n",
    "class DeepRNN(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size, num_layers, dropout=0.):\n",
    "        super(DeepRNN, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        self.num_layers = num_layers\n",
    "        self._flat_weight_names = []\n",
    "        self._all_weights = []\n",
    "        self.drop = nn.Dropout(p=dropout)\n",
    "        # 定义每一层循环神经网络的参数，由于参数数量不固定，\n",
    "        # 因此使用统一的命名方法更方便调用和管理\n",
    "        for layer in range(num_layers):\n",
    "            W_xh = nn.Parameter(normal((input_size, hidden_size)))\n",
    "            W_hh = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "            b_h = nn.Parameter(torch.zeros(hidden_size))\n",
    "            layer_params = (W_xh, W_hh, b_h)\n",
    "            params_names = [f'W_xh_l{layer}', f'W_hh_l{layer}', \\\n",
    "                f'b_h_l{layer}']\n",
    "            \n",
    "            # 将新的参数加入到成员列表中\n",
    "            for name, param in zip(params_names, layer_params):\n",
    "                setattr(self, name, param)\n",
    "            self._flat_weight_names.extend(params_names)\n",
    "            self._all_weights.append(params_names)\n",
    "            input_size = hidden_size\n",
    "        self._flat_weights = [getattr(self, wn) if hasattr(self, wn) \\\n",
    "            else None for wn in self._flat_weight_names]\n",
    "    \n",
    "    def __setattr__(self, attr, value):\n",
    "        if hasattr(self, '_flat_weight_names') and \\\n",
    "            attr in self._flat_weight_names:\n",
    "            idx = self._flat_weight_names.index(attr)\n",
    "            self._flat_weights[idx] = value\n",
    "        super().__setattr__(attr, value)\n",
    "    \n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((self.num_layers, batch_size, hidden_size), \n",
    "            dtype=torch.float),)\n",
    "    \n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        layer_hidden_states, = states\n",
    "        layer_h_t = []\n",
    "        input_states = inputs\n",
    "        # 需要保存每一层的输出作为下一层的输入\n",
    "        for layer in range(self.num_layers):\n",
    "            hiddens = []\n",
    "            hidden_state = layer_hidden_states[layer]\n",
    "            for step in range(seq_len):\n",
    "                xh = torch.mm(input_states[step], \n",
    "                    getattr(self, f'W_xh_l{layer}'))\n",
    "                hh = torch.mm(hidden_state, getattr(self, f'W_hh_l{layer}'))\n",
    "                hidden_state = xh + hh + getattr(self, f'b_h_l{layer}')\n",
    "                hidden_state = self.drop(torch.tanh(hidden_state))\n",
    "                hiddens.append(hidden_state)\n",
    "            input_states = torch.stack(hiddens, dim=0)\n",
    "            layer_h_t.append(hidden_state)\n",
    "        return input_states, torch.stack(layer_h_t, dim=0)\n",
    "\n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, dtype=torch.long), \n",
    "    batch_size=16, shuffle=True)\n",
    "deep_rnn = DeepRNN(128, 128, 2)\n",
    "train_rnn_lm(data_loader, deep_rnn, vocab_size, hidden_size=128, \n",
    "    epochs=200, learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f0f1be39",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "需要注意的是，双向循环神经网络在每个位置的输出同时包含了来自左边和右边的信息，也就是整个输入序列的信息。所以双向循环神经网络并不能用于语言模型，因为语言模型需要仅根据序列中每个词左边的信息来预测这个词。\n",
    "\n",
    "下面的双向循环神经网络是一个简单的示例，要求一次只能输入一个序列。如果想在一个批次中并行处理不同长度的输入序列以获得更高的运行效率，可以通过填充将不同长度的输入对齐。单向循环神经网络的填充较为简单，只需在每个序列末尾添加字符就可以。但是双向循环神经网络的填充更加复杂，正向和反向循环神经网络的读取顺序相反，难以保证两个方向的循环神经网络都填充在末尾，实现起来较为困难。\n",
    "解决方案参考PyTorch中的pack_padded_sequence和pad_packed_sequence。双向循环神经网络不能用于训练语言模型，因此不再提供训练示例代码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0344d588",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 双向循环神经网络\n",
    "class BiRNN(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size):\n",
    "        super(BiRNN, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        # 正向循环神经网络参数\n",
    "        self.W_xh = nn.Parameter(normal((input_size, hidden_size)))\n",
    "        self.W_hh = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_h = nn.Parameter(torch.zeros(hidden_size))\n",
    "        # 反向循环神经网络参数\n",
    "        self.W_xh_reverse = nn.Parameter(normal((input_size, hidden_size)))\n",
    "        self.W_hh_reverse = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_h_reverse = nn.Parameter(torch.zeros(hidden_size))\n",
    "        \n",
    "    # 分别为正向和反向循环神经网络准备初始状态\n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((batch_size, hidden_size), dtype=torch.float),\n",
    "               torch.zeros((batch_size, hidden_size), dtype=torch.float))\n",
    "    \n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        hidden_state, reverse_hidden_state = states\n",
    "        hiddens = []\n",
    "        for step in range(seq_len):\n",
    "            xh = torch.mm(inputs[step], self.W_xh)\n",
    "            hh = torch.mm(hidden_state, self.W_hh)\n",
    "            hidden_state = xh + hh + self.b_h\n",
    "            hidden_state = torch.tanh(hidden_state)\n",
    "            hiddens.append(hidden_state)\n",
    "        reverse_hiddens = []\n",
    "        for step in range(seq_len-1, -1, -1):\n",
    "            xh = torch.mm(inputs[step], self.W_xh_reverse)\n",
    "            hh = torch.mm(reverse_hidden_state, self.W_hh_reverse)\n",
    "            reverse_hidden_state = xh + hh + self.b_h_reverse\n",
    "            reverse_hidden_state = torch.tanh(reverse_hidden_state)\n",
    "            reverse_hiddens.insert(0, reverse_hidden_state)\n",
    "        # 将正向和反向循环神经网络输出的隐状态拼接在一起\n",
    "        combined_hiddens = []\n",
    "        for h1, h2 in zip(hiddens, reverse_hiddens):\n",
    "            combined_hiddens.append(torch.cat([h1, h2], dim=-1))\n",
    "        return torch.stack(combined_hiddens, dim=0), ()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b79ef2c6",
   "metadata": {},
   "source": [
    "下面实现一个带有缩放点乘注意力的循环神经网络，并用其训练语言模型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b5c32275",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=0.9967: 100%|█| 200/200 [09:11<00:00,  2.76s\n"
     ]
    },
    {
     "data": {
      "image/png": "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ic8++0y9v/3Uz1tvvYWgoCBs3LgRo0ePhp+fHy699FIUFxerj7HZbFi5ciWCgoIQGhqKxx9/HLfeeiuuuuqqbl/vd999h7lz58Lb2xvx8fFYuXIlGhsbXcb+7LPP4qabboKfnx9iYmLwyiuvuDxHfn4+rrzySvj5+SEgIADXXXcdSktLXa757LPPMG3aNHh5eSEsLAxXX321y/1NTU348Y9/DH9/fyQkJOC1117rdtxE1DMGFaIh6OWXX8asWbNw5513ori4GMXFxYiPj1fvf+yxx7Bq1SpkZWVhwoQJaGhowGWXXYbNmzfj4MGDWLJkCZYvX478/Pxuf84zzzyD6667DkeOHMFll12GFStWoKqqqsvrm5qa8Kc//Qn//Oc/sX37duTn5+ORRx5R7//973+P9957D2vXrsW3336Luro6rFu3rtsxZGRkYMmSJbj66qtx5MgRfPTRR9i5cyfuu+8+l+v++Mc/YsKECThw4ACeeOIJ/PznP8emTZsASJWlq666ClVVVdi2bRs2bdqE06dP4/rrr1cfv379elx99dW4/PLLcfDgQXz99deYNm2ay8944YUXMG3aNBw8eBD33HMPfvazn+H48ePdjp+IejBg5zATkVuZN2+e+MADD7jcphxdv27duh4fP2bMGPGVV15Rv09MTBT//Oc/q98DEH/961+r3zc0NIiCIIgbNmxw+VnV1dWiKIri2rVrRQBidna2+phXX31VjIyMVL+PjIwU//jHP6rf22w2MSEhQbzyyiu7HOePfvQj8a677nK5bceOHaJOpxObm5vVsV966aUu11x//fXi0qVLRVEUxa+++krU6/UuR9NnZmaKAMQ9e/aIoiiKs2bNElesWNHlOBITE8Wbb75Z/d7hcIgRERHimjVrunwMEfWMFRWiYah9JaCxsRGPPfYYxowZg6CgIPj5+eH48eM9VlQmTJig/tnX1xf+/v4oKyvr8nofHx+kpqaq30dHR6vX19bWorS0FDNmzFDv1+v1mDp1ardj2L9/P9566y34+fmpX0uWLIHD4UBubq563axZs1weN2vWLGRlZQEAsrKyEB8f71J1Uv4ulGsOHTqERYsWdTsW578PQRAQFRXV7d8HEfWMzbREw1D71TuPPvooNm7ciD/96U8YMWIEvL29cc0118BqtXb7PEaj0eV7QRDgcDj6dL0oih1uc9b+/vYcDgd++tOfYuXKlR3uS0hI6Paxys8SRbHDz21/u7e3d7fPBfT974OIesaKCtEQZTKZYLfbe3Xtjh07cNttt+EHP/gBxo8fj6ioKJw5c+b8DrCdwMBAREZGYs+ePeptdrsdBw8e7PZxU6ZMQWZmJkaMGNHhy2Qyqdft2rXL5XG7du1Ceno6AKl6kp+fj4KCAvX+Y8eOoba2FqNHjwYgVUu+/vrrc36dRNQ3rKgQDVFJSUnYvXs3zpw5Az8/P4SEhHR57YgRI/DJJ59g+fLlEAQBTz75pCaVgPvvvx+rVq3CiBEjkJ6ejldeeQXV1dWdVjsUjz/+OC644ALce++9uPPOO+Hr64usrCxs2rTJZWXPt99+iz/84Q+46qqrsGnTJnz88cdYv349AGDx4sWYMGECVqxYgZdeegk2mw333HMP5s2bp06TPfXUU1i0aBFSU1Nxww03wGazYcOGDXjsscfO718K0TDHigrREPXII49Ar9djzJgxCA8P77bf5M9//jOCg4Mxe/ZsLF++HEuWLMGUKVMGcbSSxx9/HDfeeCNuueUWzJo1S+038fLy6vIxEyZMwLZt23Dq1ClcdNFFmDx5Mp588klER0e7XPfwww9j//79mDx5Mp599lm88MILWLJkCQBpimbdunUIDg7G3LlzsXjxYqSkpOCjjz5SHz9//nx8/PHH+OyzzzBp0iQsXLgQu3fvPj9/EUSkEsSeJoCJiDTicDgwevRoXHfddXj22Wf7/TxJSUl48MEH8eCDDw7c4IhoUHDqh4jcRl5eHr766ivMmzcPFosFq1evRm5uLm666Sath0ZEGuHUDxG5DZ1Oh7feegvTp0/HnDlzkJGRgc2bN6sNrUQ0/HDqh4iIiNwWKypERETkthhUiIiIyG0xqBAREZHbYlAhIiIit8WgQkRERG6LQYWIiIjcFoMKERERuS0GFSIiInJb/w/I/E6uwbi2rAAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "class AttentionRNN(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size):\n",
    "        super(AttentionRNN, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        # 循环神经网络参数\n",
    "        self.W_xh = nn.Parameter(normal((input_size, hidden_size)))\n",
    "        self.W_hh = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_h = nn.Parameter(torch.zeros(hidden_size))\n",
    "    \n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((batch_size, hidden_size),\\\n",
    "            dtype=torch.float),)\n",
    "    \n",
    "    # 缩放点乘注意力\n",
    "    def attention(self, query, keys, values):\n",
    "        \"\"\"\n",
    "        query: batch_size * hidden_size\n",
    "        keys/values: batch_size * prev_len * hidden_size\n",
    "        \"\"\"\n",
    "        # batch_size * 1 * hidden_size\n",
    "        query = torch.unsqueeze(query, 1)\n",
    "        # batch_size * hidden_size * prev_len\n",
    "        keys = torch.permute(keys, (0, 2, 1))\n",
    "        # batch_size * 1 * prev_len\n",
    "        attention_scores = torch.bmm(query, keys) / np.sqrt(\\\n",
    "            self.hidden_size)\n",
    "        # batch_size * 1 * prev_len\n",
    "        attention_weights = F.softmax(attention_scores, dim=1)\n",
    "        # batch_size * hidden_size\n",
    "        attention_state = torch.squeeze(torch.bmm(attention_weights,\\\n",
    "            values))\n",
    "        return attention_state\n",
    "\n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        hidden_state, = states\n",
    "        hiddens = []\n",
    "        attention_hiddens = []\n",
    "        for step in range(seq_len):\n",
    "            xh = torch.mm(inputs[step], self.W_xh)\n",
    "            hh = torch.mm(hidden_state, self.W_hh)\n",
    "            hidden_state = xh + hh + self.b_h\n",
    "            hidden_state = torch.tanh(hidden_state)\n",
    "            \n",
    "            if step > 0:\n",
    "                # batch_size * hidden_size\n",
    "                query = hidden_state\n",
    "                # batch_size * prev_len * hidden_size\n",
    "                keys = values = torch.permute(torch.stack(hiddens,\\\n",
    "                    dim=0), (1, 0, 2))\n",
    "                \n",
    "                attention_state = self.attention(query, keys, values)                \n",
    "                attention_hiddens.append(attention_state)\n",
    "            else:\n",
    "                # 第0步，历史隐状态为空，无法进行注意力运算，\n",
    "                # 直接用隐状态填充\n",
    "                attention_hiddens.append(hidden_state)\n",
    "                \n",
    "            hiddens.append(hidden_state)\n",
    "        return torch.stack(attention_hiddens, dim=0), \\\n",
    "            (attention_state,)\n",
    "    \n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, dtype=torch.long), \n",
    "    batch_size=16, shuffle=True)\n",
    "\n",
    "attention_rnn = AttentionRNN(128, 128)\n",
    "train_rnn_lm(data_loader, attention_rnn, vocab_size, hidden_size=128, \n",
    "    epochs=200, learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c95d2f4b",
   "metadata": {},
   "source": [
    "下面是多头注意力的代码实现。我们在实现AttentionRNN时将注意力计算封装在成员函数里面，因此实现多头注意力时可以直接继承AttentionRNN类，只用改写构造函数和attention()成员方法即可。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6373e7ab",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=1.1583: 100%|█| 200/200 [21:31<00:00,  6.46s\n"
     ]
    },
    {
     "data": {
      "image/png": "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wuzZszFy5Ei89dZbauNeJL2fr732GhYtWoTMzEz1tnB/D7vTn/ct3N5bp9OJG264AR6PBy+//LLPfXfccYf6+cSJEzFq1CjMnDkTO3fuxPTp0wd7qH3W35/LcHsPAeD111/HzTffDJPJ5HN7OL2H3f2NAIL/u8ipHy/JycnQarVdUmB1dXWXRBlO7r33Xnz22WdYu3YtsrOze7w2IyMDw4YNw7FjxwZpdAMrJiYGkyZNwrFjx9TVP5HyfhYVFWHNmjX48Y9/3ON14f4eBvK+paenw+FwoKGhodtrQp3T6cR1112HwsJCrF692qea4s/06dOh1+vD9n3t/HMZCe8hAGzYsAFHjhzp9fcSCN33sLu/EaHyu8ig4sVgMGDGjBldynKrV6/GnDlzgjSq/hNFEffccw8+/vhjfPPNNxg+fHivj6mrq0NJSQkyMjIGYYQDz26349ChQ8jIyFBLrt7vp8PhwPr168Py/XzjjTeQmpqKSy+9tMfrwv09DOR9mzFjBvR6vc81FRUV2L9/f1i8t0pIOXbsGNasWYOkpKReH3PgwAE4nc6wfV87/1yG+3uoeO211zBjxgxMmTKl12tD7T3s7W9EyPwuDkhLbgT54IMPRL1eL7722mviwYMHxfvvv1+MiYkRT548Geyh9dldd90lWiwWcd26dWJFRYX60draKoqiKDY1NYkPPviguHHjRrGwsFBcu3atOHv2bDErK0u02WxBHn1gHnzwQXHdunViQUGBuHnzZvGyyy4TzWaz+n499dRTosViET/++GNx37594o033ihmZGSEzetTuN1uMTc3V3z44Yd9bg/X97CpqUnctWuXuGvXLhGA+Mwzz4i7du1SV70E8r7deeedYnZ2trhmzRpx586d4rx588QpU6aILpcrWC9L1dPrczqd4uWXXy5mZ2eLu3fv9vndtNvtoiiK4vHjx8Xf/va34rZt28TCwkJx1apV4tixY8Vp06aFxOsTxZ5fY6A/l+H6HiqsVqsYHR0trlixosvjw+E97O1vhCiGxu8ig4ofL730kjhs2DDRYDCI06dP91nOG04A+P144403RFEUxdbWVnHhwoViSkqKqNfrxdzcXHHp0qVicXFxcAfeB9dff72YkZEh6vV6MTMzU7zqqqvEAwcOqPd7PB7xscceE9PT00Wj0Sied9554r59+4I44v758ssvRQDi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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 多头注意力循环神经网络\n",
    "class MultiHeadAttentionRNN(AttentionRNN):\n",
    "    def __init__(self, input_size, hidden_size, num_heads=4):\n",
    "        super().__init__(input_size, hidden_size)\n",
    "        # 简单起见，一般要求hidden_size能够被num_heads整除\n",
    "        assert hidden_size % num_heads == 0\n",
    "        self.num_heads = num_heads\n",
    "        # 多头注意力参数，用于将查询、键、值映射到子空间\n",
    "        self.W_aq = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_aq = nn.Parameter(torch.zeros(hidden_size))\n",
    "        self.W_ak = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_ak = nn.Parameter(torch.zeros(hidden_size))\n",
    "        self.W_av = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_av = nn.Parameter(torch.zeros(hidden_size))\n",
    "        self.W_ac = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_ac = nn.Parameter(torch.zeros(hidden_size))\n",
    "\n",
    "    # 多头缩放点乘注意力\n",
    "    def attention(self, query, keys, values):\n",
    "        \"\"\"\n",
    "        query: batch_size * hidden_size\n",
    "        keys/values: batch_size * prev_len * hidden_size\n",
    "        \"\"\"\n",
    "        query = torch.mm(query, self.W_aq) + self.b_aq\n",
    "        ori_shape = keys.size()\n",
    "        \n",
    "        keys = torch.reshape(torch.mm(torch.flatten(keys, \n",
    "                start_dim=0, end_dim=1), self.W_ak) + \n",
    "                self.b_ak, ori_shape)\n",
    "        values = torch.reshape(torch.mm(torch.flatten(values, \n",
    "                start_dim=0, end_dim=1), self.W_av) + \n",
    "                self.b_av, ori_shape)\n",
    "        # batch_size * 1 * hidden_size\n",
    "        query = torch.unsqueeze(query, 1)\n",
    "        # batch_size * hidden_size * prev_len\n",
    "        keys = torch.permute(keys, (0, 2, 1))\n",
    "        \n",
    "        head_size = self.hidden_size // self.num_heads\n",
    "        query = torch.split(query, head_size, 2)\n",
    "        keys = torch.split(keys, head_size, 1)\n",
    "        values = torch.split(values, head_size, 2)\n",
    "        \n",
    "        heads = []\n",
    "        for i in range(self.num_heads):\n",
    "            # batch_size * 1 * prev_len\n",
    "            head_scores = torch.bmm(query[i], keys[i]) / np.sqrt(\n",
    "                self.hidden_size // self.num_heads) \n",
    "            # batch_size * 1 * prev_len\n",
    "            head_weights = F.softmax(head_scores, dim=1)\n",
    "            # batch_size * head_size\n",
    "            head_state = torch.squeeze(torch.bmm(head_weights, \n",
    "                values[i])) \n",
    "            heads.append(head_state)\n",
    "        heads = torch.cat(heads, dim=1)        \n",
    "        attention_state = torch.mm(heads, self.W_ac) + self.b_ac\n",
    "\n",
    "        return attention_state\n",
    "\n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, \n",
    "    dtype=torch.long), batch_size=16, shuffle=True)\n",
    "\n",
    "mha_rnn = MultiHeadAttentionRNN(128, 128)\n",
    "train_rnn_lm(data_loader, mha_rnn, vocab_size, hidden_size=128, \n",
    "    epochs=200, learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "166d4dce",
   "metadata": {},
   "source": [
    "下面来实现Transformer模型，包括加入了位置编码的嵌入层、缩放点乘注意力、多头注意力、层归一化等具体实现。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0e4110a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "代码修改自GitHub项目huggingface/transformers\n",
    "（Copyright (c) 2020, The HuggingFace Team, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 实现Transformer模型\n",
    "class EmbeddingLayer(nn.Module):\n",
    "    def __init__(self, vocab_size, max_len, embed_size):\n",
    "        super().__init__()\n",
    "        self.vocab_size = vocab_size\n",
    "        self.max_len = max_len\n",
    "        self.embed_size = embed_size\n",
    "        self.word_embedding = nn.Embedding(vocab_size, embed_size)\n",
    "        self.pos_embedding = nn.Embedding(max_len, embed_size)\n",
    "        \n",
    "    def forward(self, input_ids, pos_ids):\n",
    "        \"\"\"\n",
    "        input_ids/pos_ids: batch_size * seq_len\n",
    "        return: batch_size * seq_len * embed_size\n",
    "        \"\"\"\n",
    "        word_embed = self.word_embedding(input_ids)\n",
    "        pos_embed = self.pos_embedding(pos_ids)\n",
    "        # 将词嵌入和位置嵌入相加得到嵌入层输出\n",
    "        return word_embed + pos_embed\n",
    "\n",
    "# 缩放点乘注意力\n",
    "class ScaledDotProductAttention(nn.Module):\n",
    "    def __init__(self, dropout):\n",
    "        super().__init__()\n",
    "        self.dropout = nn.Dropout(dropout)\n",
    "    \n",
    "    def forward(self, queries, keys, values, attention_mask):\n",
    "        \"\"\"\n",
    "        queries/keys/values: batch_size * seq_len * hidden_size\n",
    "        attention_mask: batch_size * seq_len * seq_len\n",
    "        return: batch_size * seq_len * hidden_size\n",
    "        \"\"\"\n",
    "        d = queries.size(-1)\n",
    "        # 根据点乘注意力的矩阵形式计算注意力分数，除以查询向量或键向量\n",
    "        # 维度的平方根，即为缩放点乘注意力\n",
    "        scores = torch.bmm(queries, torch.transpose(keys, 1, 2)) / np.sqrt(d)\n",
    "        # 将掩码为0的位置的注意力分数设为一个大负数，根据softmax函数\n",
    "        # 的性质，这些注意力分数归一化后接近0\n",
    "        scores[attention_mask == 0] = -1e6\n",
    "        self.attention_weights = F.softmax(scores, dim=-1)\n",
    "        return torch.bmm(self.dropout(self.attention_weights), values)\n",
    "    \n",
    "class MultiHeadSelfAttention(nn.Module):\n",
    "    def __init__(self, hidden_size, num_heads, dropout):\n",
    "        super().__init__()\n",
    "        assert hidden_size % num_heads == 0\n",
    "        self.hidden_size = hidden_size\n",
    "        self.num_heads = num_heads\n",
    "        self.W_q = nn.Linear(hidden_size, hidden_size)\n",
    "        self.W_k = nn.Linear(hidden_size, hidden_size)\n",
    "        self.W_v = nn.Linear(hidden_size, hidden_size)\n",
    "        self.W_o = nn.Linear(hidden_size, hidden_size)\n",
    "        self.attention = ScaledDotProductAttention(dropout)\n",
    "    \n",
    "    def transpose_qkv(self, states):\n",
    "        # 将长度为hidden_size的向量分成num_heads个长度相等的向量\n",
    "        states = states.reshape(states.shape[0], states.shape[1],\\\n",
    "            self.num_heads, self.hidden_size // self.num_heads)\n",
    "        states = torch.permute(states, (0, 2, 1, 3))\n",
    "        return states.reshape(-1, states.shape[2], states.shape[3])\n",
    "    \n",
    "    # 与transpose_qkv的变换相反\n",
    "    def transpose_output(self, states):\n",
    "        states = states.reshape(-1, self.num_heads, states.shape[1],\\\n",
    "            states.shape[2])\n",
    "        states = torch.permute(states, (0, 2, 1, 3))\n",
    "        return states.reshape(states.shape[0], states.shape[1], -1)\n",
    "    \n",
    "    def forward(self, queries, keys, values, attention_mask):\n",
    "        \"\"\"\n",
    "        querys/keys/values: batch * seq_len * hidden_size\n",
    "        attention_mask: batch * seq_len * seq_len\n",
    "        return:\n",
    "        \"\"\"\n",
    "        # (batch_size * num_heads) * seq_len * (hidden_size / num_heads)\n",
    "        queries = self.transpose_qkv(self.W_q(queries))\n",
    "        keys = self.transpose_qkv(self.W_k(keys))\n",
    "        values = self.transpose_qkv(self.W_v(values))\n",
    "        # 重复张量的元素，用以支持多个注意力头的运算\n",
    "        # (batch_size * num_heads) * seq_len * seq_len\n",
    "        attention_mask = torch.repeat_interleave(attention_mask,\\\n",
    "            repeats=self.num_heads, dim=0)\n",
    "        # (batch_size * num_heads) * seq_len * (hidden_size / num_heads)\n",
    "        output = self.attention(queries, keys, values, attention_mask)\n",
    "        # batch * seq_len * hidden_size\n",
    "        output_concat = self.transpose_output(output)\n",
    "        return self.W_o(output_concat)\n",
    "\n",
    "# 两层前馈神经网络\n",
    "class PositionWiseFNN(nn.Module):\n",
    "    def __init__(self, hidden_size, intermediate_size):\n",
    "        super().__init__()\n",
    "        self.dense1 = nn.Linear(hidden_size, intermediate_size)\n",
    "        self.relu = nn.ReLU()\n",
    "        self.dense2 = nn.Linear(intermediate_size, hidden_size)\n",
    "        \n",
    "    def forward(self, X):\n",
    "        return self.dense2(self.relu(self.dense1(X)))\n",
    "\n",
    "# 层归一化\n",
    "class LayerNorm(nn.Module):\n",
    "    def __init__(self, normalized_shape, eps=1e-6):\n",
    "        super().__init__()\n",
    "        self.gamma = nn.Parameter(torch.ones(normalized_shape))\n",
    "        self.beta = nn.Parameter(torch.zeros(normalized_shape))\n",
    "        # 一个小量用于数值稳定（防止除0）\n",
    "        self.eps = eps\n",
    "        \n",
    "    def forward(self, hidden_states):\n",
    "        mean = torch.mean(hidden_states, -1, keepdim=True)\n",
    "        std = torch.std(hidden_states, -1, keepdim=True)\n",
    "        return self.gamma * (hidden_states - mean) / (std +\\\n",
    "            self.eps) + self.beta\n",
    "\n",
    "# 将两个输入相加并归一化\n",
    "class AddNorm(nn.Module):\n",
    "    def __init__(self, hidden_size, dropout):\n",
    "        super().__init__()\n",
    "        self.dropout = nn.Dropout(dropout)\n",
    "        self.layer_norm = LayerNorm(hidden_size)\n",
    "        \n",
    "    def forward(self, X, Y):\n",
    "        return self.layer_norm(self.dropout(Y) + X)\n",
    "    \n",
    "# 一个完整的Transformer层\n",
    "class TransformerLayer(nn.Module):\n",
    "    def __init__(self, hidden_size, num_heads, dropout, intermediate_size):\n",
    "        super().__init__()\n",
    "        self.self_attention = MultiHeadSelfAttention(hidden_size,\\\n",
    "            num_heads, dropout)\n",
    "        self.add_norm1 = AddNorm(hidden_size, dropout)\n",
    "        self.fnn = PositionWiseFNN(hidden_size, intermediate_size)\n",
    "        self.add_norm2 = AddNorm(hidden_size, dropout)\n",
    "    \n",
    "    def forward(self, X, attention_mask):\n",
    "        Y = self.add_norm1(X, self.self_attention(X, X, X, attention_mask))\n",
    "        return self.add_norm2(Y, self.fnn(Y))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2fd3f8f4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在Transformer模型基础上加上语言模型需要的输入输出、损失计算等\n",
    "class TransformerLM(nn.Module):\n",
    "    def __init__(self, vocab_size, max_len, hidden_size, num_layers,\\\n",
    "                 num_heads, dropout, intermediate_size):\n",
    "        super().__init__()\n",
    "        self.embedding_layer = EmbeddingLayer(vocab_size, max_len,\\\n",
    "            hidden_size)\n",
    "        self.num_layers = num_layers\n",
    "        # 使用ModuleList保存多个Transformer层，注意不能使用Python列表，\n",
    "        # Python列表保存的PyTorch变量无法自动求导\n",
    "        self.layers = nn.ModuleList([TransformerLayer(hidden_size,\\\n",
    "            num_heads, dropout, intermediate_size)\\\n",
    "            for _ in range(num_layers)])\n",
    "        self.output_layer = nn.Linear(hidden_size, vocab_size)\n",
    "        \n",
    "    def forward(self, input_ids):\n",
    "        # 这里实现的forward()函数一次只能处理一句话，\n",
    "        # 如果想要支持批次运算，实现起来会更复杂，也会引入冗余操作\n",
    "        seq_len = input_ids.size(0)\n",
    "        assert input_ids.ndim == 1 and seq_len <= \\\n",
    "            self.embedding_layer.max_len\n",
    "        \n",
    "        # 1 * seq_len\n",
    "        input_ids = torch.unsqueeze(input_ids, dim=0)\n",
    "        pos_ids = torch.unsqueeze(torch.arange(seq_len), dim=0)\n",
    "        # 定义下三角掩码，用于语言模型训练\n",
    "        # 1 * seq_len * seq_len\n",
    "        attention_mask = torch.unsqueeze(torch.tril(torch.ones((seq_len,\\\n",
    "            seq_len), dtype=torch.int32)), dim=0)\n",
    "        # 1 * seq_len * hidden_size\n",
    "        hidden_states = self.embedding_layer(input_ids, pos_ids)\n",
    "        for layer in self.layers:\n",
    "            hidden_states = layer(hidden_states, attention_mask)\n",
    "        outputs = self.output_layer(hidden_states)\n",
    "        \n",
    "        loss_fct = nn.CrossEntropyLoss(ignore_index=0)\n",
    "        loss = loss_fct(outputs[:, :-1].squeeze(),\\\n",
    "            input_ids[:, 1:].squeeze())\n",
    "        return loss"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e459fc19",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-49, loss=1.3295: 100%|█| 50/50 [08:23<00:00, 10.06s/it\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 训练TransformerLM，由于不再采取批次训练，因此不再使用RNNLM和data_loader\n",
    "def train_transformer_lm(data, model, epochs=50, learning_rate=1e-3):\n",
    "    optimizer = Adam(model.parameters(), lr=learning_rate)\n",
    "    model.zero_grad()\n",
    "    model.train()\n",
    "    \n",
    "    epoch_loss = []\n",
    "    with trange(epochs, desc='epoch', ncols=60) as pbar:\n",
    "        for epoch in pbar:\n",
    "            step_loss = []\n",
    "            np.random.shuffle(data)\n",
    "            for step, x in enumerate(data):\n",
    "                loss = model(torch.tensor(x, dtype=torch.long))\n",
    "                pbar.set_description(f'epoch-{epoch},'+\\\n",
    "                    f' loss={loss.item():.4f}')\n",
    "                loss.backward()\n",
    "                grad_clipping(model)\n",
    "                optimizer.step()\n",
    "                model.zero_grad()\n",
    "                step_loss.append(loss.item())\n",
    "            # 本章前面的模型训练使用batch_size为16，\n",
    "            # TransformerLM出于简便实现只能使用batch_size为1\n",
    "            # 因此TransformerLM每一步的损失方差会更大，\n",
    "            # 为便于对比，取每个epoch最后16个样本的平均损失\n",
    "            epoch_loss.append(np.mean(step_loss[-16:]))\n",
    "    \n",
    "    epoch_loss = np.array(epoch_loss)\n",
    "    plt.plot(range(len(epoch_loss)), epoch_loss)\n",
    "    plt.xlabel('training epoch')\n",
    "    plt.ylabel('loss')\n",
    "    plt.show()\n",
    "    \n",
    "sent_tokens = dataset.convert_tokens_to_ids()\n",
    "max_len=40\n",
    "for i, tokens in enumerate(sent_tokens):\n",
    "    tokens = tokens[:max_len]\n",
    "    tokens += [0] * (max_len - len(tokens))\n",
    "    sent_tokens[i] = tokens\n",
    "sent_tokens = np.array(sent_tokens)\n",
    "\n",
    "model = TransformerLM(vocab_size, max_len=40, hidden_size=128,\\\n",
    "    num_layers=1, num_heads=4, dropout=0., intermediate_size=512)\n",
    "train_transformer_lm(sent_tokens, model)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
